//###########################################################################
// FILE:   F2837xD_Ipc_Driver_Util.c
// TITLE:  F2837xD Inter-Processor Communication (IPC) API Driver Utility
//         Functions
// DESCRIPTION:
//         API functions for inter-processor communications between the
//         Local and Remote CPU system.
//         The driver functions in this file are available only as
//         sample functions for application development.  Due to the generic
//         nature of these functions and the cycle overhead inherent to a
//         function call, the code is not intended to be used in cases where
//         maximum efficiency is required in a system.
//
// NOTE:   This source code is used by both CPUs. That is both CPU1 and CPU2 
//         cores use this code. 
//         The active debug CPU will be referred to as Local CPU and the other
//         CPU will be referred to as Remote CPU.
//         When using this source code in CPU1, the term "local"
//         will mean CPU1 and the term "remote" CPU will be mean CPU2. 
//         When using this source code in CPU2, the term "local"
//         will mean CPU2 and the term "remote" CPU will be mean CPU1. 
//
//         The abbreviations LtoR and RtoL  within the function names mean
//         Local to Remote and Remote to Local respectively.
//
//###########################################################################
// $TI Release: F2837xD Support Library v160 $
// $Release Date: Mon Jun 15 13:36:23 CDT 2015 $
// $Copyright: Copyright (C) 2013-2015 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//*****************************************************************************
//! \addtogroup ipc_util_api
//! @{
//*****************************************************************************
#include <F2837xD_device.h>     // Headerfile Include File
#include <F2837xD_GlobalPrototypes.h>
#include <F2837xD_Gpio_defines.h>
#include <F2837xD_Ipc_drivers.h>

//*****************************************************************************
//! Local CPU Acknowledges Remote to Local IPC Flag.
//!
//! \param ulFlags specifies the IPC flag mask for flags being acknowledged.
//!
//! This function will allow the Local CPU system to acknowledge/clear the IPC
//! flag set by the Remote CPU system. The \e ulFlags parameter can be any of
//! the IPC flag values: \b IPC_FLAG0 - \b IPC_FLAG31.
//!
//! \return None.
//*****************************************************************************
void
IPCRtoLFlagAcknowledge (uint32_t ulFlags)
{
    IpcRegs.IPCACK.all |= ulFlags;
}

//*****************************************************************************
//! Determines whether the given Remote to Local IPC flags are busy or not.
//!
//! \param ulFlags specifies Remote to Local IPC Flag number masks to check the status of.
//!
//! Allows the caller to determine whether the designated IPC flags are
//! pending. The \e ulFlags parameter can be any of the IPC flag
//! values: \b IPC_FLAG0 - \b IPC_FLAG31.
//!
//! \return Returns \b 1 if the IPC flags are busy or \b 0 if designated
//! IPC flags are free.
//*****************************************************************************
Uint16
IPCRtoLFlagBusy (uint32_t ulFlags)
{
    Uint16 returnStatus;
    
    if ((IpcRegs.IPCSTS.all & ulFlags) == 0)
    {
        returnStatus = 0;
    }
    else
    {
        returnStatus = 1;
    }
    
    return returnStatus;
}

//*****************************************************************************
//! Determines whether the given IPC flags are busy or not.
//!
//! \param ulFlags specifies Local to Remote IPC Flag number masks to check the status
//! of.
//!
//! Allows the caller to determine whether the designated IPC flags are
//! available for further control to master system communication. If \b 0 is
//! returned, then all designated tasks have completed and are available.
//! The \e ulFlags parameter can be any of the IPC flag
//! values: \b IPC_FLAG0 - \b IPC_FLAG31.
//!
//! \return Returns \b 1 if the IPC flags are busy or \b 0 if designated
//! IPC flags are free.
//*****************************************************************************
Uint16
IPCLtoRFlagBusy (uint32_t ulFlags)
{
    Uint16 returnStatus;
    
    if ((IpcRegs.IPCFLG.all & ulFlags) == 0)
    {
        returnStatus = 0;
    }
    else
    {
        returnStatus = 1;
    }
    
    return returnStatus;
}

//*****************************************************************************
//! Local CPU Sets Local to Remote IPC Flag
//!
//! \param ulFlags specifies the IPC flag mask for flags being set.
//!
//! This function will allow the Local CPU system to set the designated IPC
//! flags to send to the Remote CPU system. The \e ulFlags parameter can be any
//! of the IPC flag values: \b IPC_FLAG0 - \b IPC_FLAG31.
//!
//! \return None.
//*****************************************************************************
void
IPCLtoRFlagSet (uint32_t ulFlags)
{
    IpcRegs.IPCSET.all |= ulFlags;
}

//*****************************************************************************
//! Local CPU Clears Local to Remote IPC Flag
//!
//! \param ulFlags specifies the IPC flag mask for flags being set.
//!
//! This function will allow the Local CPU system to set the designated IPC
//! flags to send to the Remote CPU system. The \e ulFlags parameter can be any
//! of the IPC flag values: \b IPC_FLAG0 - \b IPC_FLAG31.
//!
//! \return None.
//*****************************************************************************
void
IPCLtoRFlagClear (uint32_t ulFlags)
{
    IpcRegs.IPCCLR.all |= ulFlags;
}

//*****************************************************************************
//! Local Return CPU02 BOOT status
//!
//! This function returns the value at IPCBOOTSTS register.
//!
//! \return Boot status.
//*****************************************************************************
uint32_t
IPCGetBootStatus (void)
{

   return(IpcRegs.IPCBOOTSTS);

}

#if defined (CPU1)
//*****************************************************************************
//! Executes a CPU02 control system bootloader.
//!
//! \param ulBootMode specifies which CPU02 control system boot mode to execute.
//!
//! This function will allow the CPU01 master system to boot the CPU02 control
//! system via the following modes: Boot to RAM, Boot to Flash, Boot via SPI,
//! SCI, I2C, or parallel I/O. Unlike other IPCLite driver functions, this
//! function blocks and waits until the control system boot ROM is configured
//! and ready to receive CPU01 to CPU02 IPC INT0 interrupts. It then blocks and waits
//! until IPC INT0 and IPC FLAG31 are available in the CPU02 boot ROM prior to
//! sending the command to execute the selected bootloader. The \e
//! ulBootMode parameter accepts one of the following values: \b
//! C1C2_BROM_BOOTMODE_BOOT_FROM_PARALLEL, \b
//! C1C2_BROM_BOOTMODE_BOOT_FROM_SCI, \b
//! C1C2_BROM_BOOTMODE_BOOT_FROM_SPI, \b
//! C1C2_BROM_BOOTMODE_BOOT_FROM_I2C, \b C1C2_BROM_BOOTMODE_BOOT_FROM_CAN,
//! \b C1C2_BROM_BOOTMODE_BOOT_FROM_RAM, \b
//! C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH.
//!
//! \return 0 (success) if command is sent, or 1 (failure) if boot mode is
//! invalid and command was not sent.
//*****************************************************************************
uint16_t 
IPCBootCPU2(uint32_t ulBootMode)
{
	uint32_t bootStatus;
    uint16_t pin;
    uint16_t returnStatus = STATUS_PASS;
    
	// If CPU2 has already booted, return a fail to let the application 
    // know that something is out of the ordinary.

    bootStatus = IPCGetBootStatus() & 0x0000000F;

	if(bootStatus == C2_BOOTROM_BOOTSTS_C2TOC1_BOOT_CMD_ACK)
    {
        returnStatus = STATUS_FAIL;
		
		return returnStatus;
    }

    // Wait until CPU02 control system boot ROM is ready to receive 
    // CPU01 to CPU02 INT1 interrupts. 
    do
    {
        bootStatus = IPCGetBootStatus() & 0x0000000F;
    } while ((bootStatus != C2_BOOTROM_BOOTSTS_SYSTEM_READY));
             

    
    // Loop until CPU02 control system IPC flags 1 and 32 are available
    while ((IPCLtoRFlagBusy(IPC_FLAG0) == 1) || 
           (IPCLtoRFlagBusy(IPC_FLAG31) == 1))
    {

    }

    if (ulBootMode >= C1C2_BROM_BOOTMODE_BOOT_COMMAND_MAX_SUPPORT_VALUE)
    {
        returnStatus = STATUS_FAIL;
    }
    else
    {
        // Based on boot mode, enable pull-ups on peripheral pins and 
        // give GPIO pin control to CPU02 control system.
        switch (ulBootMode)
        {
            case C1C2_BROM_BOOTMODE_BOOT_FROM_SCI:

                 EALLOW;
                 //SCIA connected to CPU02
                 DevCfgRegs.CPUSEL5.bit.SCI_A = 1;	
                 //Allows CPU02 bootrom to take control of clock 
                 //configuration registers
                 ClkCfgRegs.CLKSEM.all = 0xA5A50000;	

                 ClkCfgRegs.LOSPCP.all = 0x0002;
                 EDIS;
                 
                 GPIO_SetupPinOptions(29, GPIO_OUTPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(29,GPIO_MUX_CPU2,1);
                 
                 GPIO_SetupPinOptions(28, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(28,GPIO_MUX_CPU2,1);
                 
                break;

            case C1C2_BROM_BOOTMODE_BOOT_FROM_SPI:
                 EALLOW;
                 //SPI-A connected to CPU02
                 DevCfgRegs.CPUSEL6.bit.SPI_A = 1;	
                 //Allows CPU02 bootrom to take control of clock configuration registers
                 ClkCfgRegs.CLKSEM.all = 0xA5A50000;
                 EDIS;
                 
                 GPIO_SetupPinOptions(16, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(16,GPIO_MUX_CPU2,1);
                 
                 GPIO_SetupPinOptions(17, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(17,GPIO_MUX_CPU2,1);
                 
                 GPIO_SetupPinOptions(18, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(18,GPIO_MUX_CPU2,1);
                 
                 GPIO_SetupPinOptions(19, GPIO_OUTPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(19,GPIO_MUX_CPU2,0);          
                 
                break;
                
            case C1C2_BROM_BOOTMODE_BOOT_FROM_I2C:
                 EALLOW;
                 //I2CA connected to CPU02
                 DevCfgRegs.CPUSEL7.bit.I2C_A = 1;	
                 //Allows CPU2 bootrom to take control of clock 
                 //configuration registers
                 ClkCfgRegs.CLKSEM.all = 0xA5A50000;	
                 ClkCfgRegs.LOSPCP.all = 0x0002;
                 EDIS;
                 GPIO_SetupPinOptions(32, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(32,GPIO_MUX_CPU2,1);
                 
                 GPIO_SetupPinOptions(33, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(33,GPIO_MUX_CPU2,1);
                 
                break;
            case C1C2_BROM_BOOTMODE_BOOT_FROM_PARALLEL:
                 
                 
                 for(pin=58;pin<=65;pin++)
                 {
                    GPIO_SetupPinOptions(pin, GPIO_INPUT, GPIO_ASYNC);
                    GPIO_SetupPinMux(pin,GPIO_MUX_CPU2,0);
                 }
                 
                 GPIO_SetupPinOptions(69, GPIO_OUTPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(69,GPIO_MUX_CPU2,0);
                 
                 GPIO_SetupPinOptions(70, GPIO_INPUT, GPIO_ASYNC);
                 GPIO_SetupPinMux(70,GPIO_MUX_CPU2,0);             
                 break;
               
               
            case C1C2_BROM_BOOTMODE_BOOT_FROM_CAN:
                 //Set up the GPIO mux to bring out CANATX on GPIO71 
                 //and CANARX on GPIO70
                 EALLOW;
                 GpioCtrlRegs.GPCLOCK.all = 0x00000000;	//Unlock GPIOs 64-95
                 GpioCtrlRegs.GPCCSEL1.bit.GPIO71 = GPIO_MUX_CPU2;	//Give CPU2 control just in case
                 GpioCtrlRegs.GPCGMUX1.bit.GPIO71 = 0x1;	//Set the extended mux to 0x5
                 GpioCtrlRegs.GPCMUX1.bit.GPIO71 = 0x1;
                 GpioCtrlRegs.GPCQSEL1.bit.GPIO71 = 0x3;	//Set qualification to async just in case
                 
                 GpioCtrlRegs.GPCLOCK.all = 0x00000000;	//Unlock GPIOs 64-95
                 GpioCtrlRegs.GPCCSEL1.bit.GPIO70 = GPIO_MUX_CPU2;	//Give CPU2 control just in case
                 GpioCtrlRegs.GPCGMUX1.bit.GPIO70 = 0x1;	//Set the extended mux to bring out CANATX
                 GpioCtrlRegs.GPCMUX1.bit.GPIO70 = 0x1;
                 GpioCtrlRegs.GPCQSEL1.bit.GPIO70 = 0x3;	//Set qualification to async just in case
                 GpioCtrlRegs.GPCLOCK.all = 0xFFFFFFFF;	//Lock GPIOs 64-95
                 ClkCfgRegs.CLKSRCCTL2.bit.CANABCLKSEL = 0x0;
                 CpuSysRegs.PCLKCR10.bit.CAN_A = 1;
                 EDIS;   
               
               break;
               
         }
       
        //CPU01 to CPU02 IPC Boot Mode Register
        IpcRegs.IPCBOOTMODE = ulBootMode;
        // CPU01 To CPU02 IPC Command Register
        IpcRegs.IPCSENDCOM  = BROM_IPC_EXECUTE_BOOTMODE_CMD;
        // CPU01 to CPU02 IPC flag register
        IpcRegs.IPCSET.all = 0x80000001;
               
    }
  


    return returnStatus;
}


#endif
//*****************************************************************************
// Close the Doxygen group.
//! @}
//*****************************************************************************


